(function () {                                                                 
    var swapper =                                                               
        function (a,L,e) {                                                     
            var r = Math.floor(Math.random()*L);                               
            var x = a[e];                                                       
            a[e] = a[r];                                                       
            a[r] = x;                                                           
        };                                                                     
    Array.prototype.shuffle =                                                   
        function () {                                                           
            var i,L;                                                           
            i = L = this.length;                                               
            while (i--) swapper(this,L,i);                                     
        };                                                                     
})();
(function($){
	$.fn.blockgame = function(opts){
		var defaults = {
			block1:'',
			block2:'',
			block3:'',
			block4:'',
			block5:'',
			block6:'',
			block7:'',
			block8:'',
			blank:''
		};
		
		var o = $.extend(defaults,opts);
		
		var el = $(this);
		el.html(
			'<table class="blockgame"><tbody>'
			+'<tr class="row1"><td class="cell1 block">1</td><td class="cell2 block">2</td><td class="cell3 block">3</td></tr>'
			+'<tr class="row2"><td class="cell1 block">4</td><td class="cell2 block">5</td><td class="cell3 block">6</td></tr>'
			+'<tr class="row3"><td class="cell1 block">7</td><td class="cell2 block">8</td><td class="cell3"></td></tr>'
			+'</tbody></table>'
		);
		
		o['board'] = el;
		
		return new $.block8(o);
	};
	
	$.block8 = function(opt){
		var gameboard = this;
		this.opt = opt;
		this.board = opt['board'];
		this.success_case = [1,2,3,4,5,6,7,8,0];
		this.get = function(cell){
			var sel = '.row'+cell.x+' > .cell'+cell.y;
			return this.board.find(sel);
		};
		this.get_cell = function(row,cell) {
			var index = ((row-1)*3) + (cell-1);
			return this.cells[index];
		};
		this.shuffle = function(){
			var arr = this.current_case();
			arr.shuffle();
			for( var i = 0; i < 9 ; i++ ) {
				this.cells[i].value(arr[i]);
			}
		}
		this.swap = function(cell1, cell2) {
			//temporary cell holds old value while switching
			var v1 = cell1.value();
			var v2 = cell2.value();
			cell1.value(v2);
			cell2.value(v1);
		};
		this.current_case = function(){
			var arr = [];
			for( var i =0; i < 9; i++) {
				arr.push(this.cells[i].value());
			}
			return arr;
		};
		this.current_position = function(){
			for( var i in this.cells) {
				if ( this.cells[i].value() == 0 ) {
					return this.cells[i];
				}
			}
			alert('an error occured, could not find empty cell.');
			return null;
		};
		cell = function(obj){
			this.row = obj.row?obj.row:1;
			this.cell = obj.cell?obj.cell:1;
			this.sel = '.row'+this.row+' .cell'+this.cell;
			this.el = gameboard.board.find(this.sel);
			this.value = function(new_val){
				if (new_val != undefined) {
					if (new_val > 0) {
						this.el.addClass('block');
						this.el.html(new_val);
					} else {
						this.el.removeClass('block');
						this.el.html('');
					}
				}
				var val = parseInt(this.el.html());
				return val > 0 ? val : 0;
				
			};
		};
		this.ai = {
			moves:0,
			game:this,
			history: [],
			depth: 1,
			max_depth: 15,
			pause:400,
			cases_equal:function(c1,c2){
				for( var i in c1 ) {
					if ( c1[i] != c2[i] ){
						return false;
					}
				}
				return true;
			},
			case_duplicate:function(c1){
				for( var i in this.history ) {
					if ( this.cases_equal(c1,this.history[i]) ) {
						return true;
					}
				}
				return false;
			},
			start:function(){
				var success = false;
				while( this.depth <= this.max_depth ) {
					if ( this.guess() ) {
						success = true;
						break;
					}
					if ( this.depth > 9 ) {
						alert('did not find solution at depth '+this.depth+' movin\' on...');
					}
					this.depth++;
				}
				if ( success ) {
					alert("Found answer!!!");
				} else {
					alert("Failed to find answer!!!");
				}
			},
			guess:function(){
				var current_case = this.game.current_case();
				var current_position = this.game.current_position();
				if ( this.is_goal(current_case) ){
					this.history.push(current_case);
					return true;
				}
				if ( this.case_duplicate(current_case) ) {
					return false;
				}
				this.history.push(current_case);
				var available = this.available_moves(current_position);
				
				var success = false;
				if ( available.length > 0 ) {
					for ( var i = 0; i < available.length; i++ ) {
						this.game.swap(current_position, available[i]);
						if ( this.guess() ) {
							success = true;
							break;
						} else {
							this.game.swap(available[i],current_position);
						}
					}
				}
				this.history.pop();
				return success;
			},
			is_goal:function(c1){
				return this.cases_equal(this.game.success_case, c1);
			},
			available_moves:function(c){
				var av = [];
				if ( this.history.length <= this.depth ) {
					if ( c.row > 1 ) {
						av.push(this.game.get_cell(c.row-1,c.cell));
					}
					if ( c.row < 3 ) {
						av.push(this.game.get_cell(c.row+1,c.cell));
					}
					if ( c.cell > 1 ) {
						av.push(this.game.get_cell(c.row,c.cell-1));
					}
					if ( c.cell < 3 ) {
						av.push(this.game.get_cell(c.row,c.cell+1));
					}
				}
				return av;
			}
		};
		this.cells = [new cell({row:1,cell:1}),
		              new cell({row:1,cell:2}),
		              new cell({row:1,cell:3}),
		              new cell({row:2,cell:1}),
		              new cell({row:2,cell:2}),
		              new cell({row:2,cell:3}),
		              new cell({row:3,cell:1}),
		              new cell({row:3,cell:2}),
		              new cell({row:3,cell:3})];	
	};
})(jQuery);